package com.lzw.DailyAudit.service.generateInvoices_03;


import cn.hutool.core.bean.BeanUtil;
import com.hooya.fa.eu.biz.DailyAudit.entity.DailyAuditStatus;
import com.hooya.fa.eu.biz.DailyAudit.entity.InvInvoice;
import com.hooya.fa.eu.biz.DailyAudit.entity.InvInvoiceDtl;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.InvoiceDataDTO;
import com.hooya.fa.eu.biz.DailyAudit.mapper.*;
import com.hooya.fa.eu.biz.DailyAudit.service.dateAggregation_02.CommonService;
import com.xxl.job.core.context.XxlJobHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class Insert_Add_Invoice {

    @Autowired
    private DailyStkOrigDataCollectMapper stkOrigdataCollectMapper;

    @Autowired
    private DailyInvInvoiceMapper invInvoiceMapper;

    @Autowired
    private DailyInvInvoiceDtlMapper invInvoiceDtlMapper;

    @Autowired
    private DailyMetaProductMapper metaProductMapper;

    @Autowired
    private DailyMetaCorpHeaderMapper metaCorpHeaderMapper;

    @Autowired
    private DailyMetaStkShipmentMapper metaStkShipmentMapper;

	@Autowired
	private DailyAuditStatusMapper statusMapper;

	@Autowired
	private CommonService commonService;

	public void insert_add_invoice(String currentDate) {
		try {

			String name = "insert_add_invoice-03";
			DailyAuditStatus dailyAuditStatus = statusMapper.selectStatus(name, currentDate);
			if(dailyAuditStatus != null && dailyAuditStatus.getFlag() == 1){
				log.info("{} - 该方法已执行，进行跳过！",name);
				return;
			}

			log.info("开始执行添加发票步骤，开始日期：{}", currentDate);

            // 获取原始数据
            Map<String, Object> origDataMap = getOrigAddData(currentDate);
            List<InvoiceDataDTO> origGenerateData = (List<InvoiceDataDTO>) origDataMap.get("generateData");
            List<InvoiceDataDTO> origDetailData = (List<InvoiceDataDTO>) origDataMap.get("detailData");


            // 获取税号数据
            List<InvoiceDataDTO> taxIdData = getTaxid();
            // 生成发票明细
            List<InvoiceDataDTO> invoiceDtl = generateInvoiceDtl(origDetailData);
            // 添加信息
            List<InvoiceDataDTO> detailData = addInfos(invoiceDtl);
            // 添加税号
            List<InvoiceDataDTO> generateData = addTaxid(origGenerateData, taxIdData);


            // 转换为实体类并保存
            List<InvInvoiceDtl> invInvoiceDtls = convertToInvInvoiceDtl(detailData);
            List<InvInvoice> invInvoices = convertToInvInvoice(generateData);
            // 批量插入数据
            batchInsertInvoices(invInvoices);
            batchInsertInvoiceDtls(invInvoiceDtls);

			// 修改执行状态
			commonService.UpdateOrInsertStatus(dailyAuditStatus, name, currentDate);

			log.info("添加发票步骤执行完成");
			XxlJobHelper.log("添加发票步骤执行完成");
        } catch (Exception e) {
            log.error("添加发票步骤执行失败", e);
			XxlJobHelper.log("添加发票步骤执行失败");
            throw new RuntimeException("添加发票步骤执行失败", e);
        }
    }

    /**
     * 获取原始附加数据
     */
    private Map<String, Object> getOrigAddData(String currentDate) {
        Map<String, Object> result = new HashMap<>();

        List<InvoiceDataDTO> b2bGenerateData = stkOrigdataCollectMapper.getB2bGenerateData(currentDate);
        b2bGenerateData.forEach(f -> {
            f.setFullseller(f.getFullseller().toLowerCase());
            f.setFullbuyer(f.getFullbuyer().toLowerCase());
        });

        List<InvoiceDataDTO> b2bDetailData = stkOrigdataCollectMapper.getB2bDetailData(currentDate);

        result.put("generateData", b2bGenerateData);
        result.put("detailData", b2bDetailData);
        return result;
    }

    public List<InvoiceDataDTO> getTaxid() {
        List<InvoiceDataDTO> taxIdData = metaCorpHeaderMapper.getTaxid();
        taxIdData.forEach(f -> f.setCorp(f.getCorp().toLowerCase()));
        return taxIdData;
    }

    /**
     * 生成发票明细
     */
    public List<InvoiceDataDTO> generateInvoiceDtl(List<InvoiceDataDTO> data) {
        // 按invoiceId和sku等字段分组并汇总qty
        Map<String, List<InvoiceDataDTO>> grouped = data.stream()
                .collect(Collectors.groupingBy(dto ->
                        dto.getInvoiceId() + "|" + dto.getSku() + "|" + dto.getBelongs() + "|" +
                                dto.getPrice() + "|" + dto.getExportprice() + "|" + dto.getOceanfee() + "|" + dto.getType()));

        return grouped.values().stream()
                .map(group -> {
                    InvoiceDataDTO first = group.get(0);
                    InvoiceDataDTO result = new InvoiceDataDTO();
                    BeanUtils.copyProperties(first, result);

                    // 汇总qty
                    int totalQty = group.stream()
                            .mapToInt(dto -> dto.getQty() != null ? dto.getQty() : 0)
                            .sum();
                    result.setQty(totalQty);

                    return result;
                })
                .collect(Collectors.toList());
    }

    /**
     * 添加信息
     */
    public List<InvoiceDataDTO> addInfos(List<InvoiceDataDTO> data) {
        // 按belongs分组处理
        Map<String, List<InvoiceDataDTO>> groupedByBelongs = data.stream()
                .collect(Collectors.groupingBy(dto -> dto.getBelongs() != null ? dto.getBelongs() : "null"));
        List<InvoiceDataDTO> result = new ArrayList<>();
        for (Map.Entry<String, List<InvoiceDataDTO>> entry : groupedByBelongs.entrySet()) {
            String key = entry.getKey();
            List<InvoiceDataDTO> valueData = entry.getValue();

            // 添加海关编码
            List<InvoiceDataDTO> withHscode = addHscode(valueData, key);
            result.addAll(withHscode);
        }

        // 处理没有海关编码的数据
        List<InvoiceDataDTO> withHscode = result.stream()
                .filter(dto -> dto.getHscode() != null)
                .collect(Collectors.toList());
        List<InvoiceDataDTO> withoutHscode = result.stream()
                .filter(dto -> dto.getHscode() == null)
                .collect(Collectors.toList());


        // 为没有海关编码的数据添加其他海关编码
        List<InvoiceDataDTO> withOtherHscode = addHscode(withoutHscode, "all");

        // 添加异常海关编码
        List<InvoiceDataDTO> withAbnormalHscode = addAbnormalHscode(withOtherHscode);

        // 合并所有数据
        List<InvoiceDataDTO> withAllHscode = new ArrayList<>(withHscode);
        withAllHscode.addAll(withAbnormalHscode);

        if (!(data.size() == withAllHscode.size())) {
            log.error("数据不一致");
            throw new RuntimeException("数据不一致");
        }

        // 添加描述信息
        List<InvoiceDataDTO> descriptionData = metaProductMapper.getDescription();

        // 使用LinkedHashMap保持插入顺序
        descriptionData = new ArrayList<>(
                descriptionData.stream()
                        .collect(Collectors.toMap(
                                InvoiceDataDTO::getSku,
                                item -> item,
                                (first, second) -> first,  // 冲突时保留第一个
                                LinkedHashMap::new         // 保持插入顺序
                        )).values()
        );

        //左连接操作
        Map<String, List<InvoiceDataDTO>> descriptionDataMap = descriptionData.stream().collect(Collectors.groupingBy(InvoiceDataDTO::getSku));
        List<InvoiceDataDTO> withDescription = new ArrayList<>();
        for (InvoiceDataDTO mainItem : withAllHscode) {
            String key = mainItem.getSku();
            if (descriptionDataMap.containsKey(key)) {
                List<InvoiceDataDTO> InvoiceDataDTOS = descriptionDataMap.get(key);
                InvoiceDataDTOS.forEach(f -> {
                    InvoiceDataDTO newItem = new InvoiceDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setDescription(f.getDescription());
                    newItem.setWeight(f.getWeight());
                    withDescription.add(newItem);
                });
            } else {
                withDescription.add(mainItem);
            }
        }

        return withDescription;
    }

    /**
     * 添加海关编码
     */
    private List<InvoiceDataDTO> addHscode(List<InvoiceDataDTO> data, String belongs) {
        List<InvoiceDataDTO> hsCodeData;
        if (belongs.equals("costway-pl")) {
            hsCodeData = metaStkShipmentMapper.getHscodeDataByBelongsIsCostwayPl();
        } else if (belongs.equals("costway-fr")) {
            hsCodeData = metaStkShipmentMapper.getHscodeDataByBelongsIsCostwayFr();
        } else if (belongs.equals("costway-de")) {
            hsCodeData = metaStkShipmentMapper.getHscodeDataByBelongsIsCostwayDe();
        } else if (belongs.startsWith("fds")) {
            hsCodeData = metaStkShipmentMapper.getHscodeDataByBelongsIsFds();
        } else {
            hsCodeData = metaStkShipmentMapper.getHscodeDataByBelongsIsAny();
        }
        if (!hsCodeData.isEmpty()) {
            // 使用LinkedHashMap保持插入顺序
            hsCodeData = new ArrayList<>(
                    hsCodeData.stream()
                            .collect(Collectors.toMap(
                                    InvoiceDataDTO::getSku,
                                    item -> item,
                                    (first, second) -> first,  // 冲突时保留第一个
                                    LinkedHashMap::new         // 保持插入顺序
                            )).values()
            );
        }
        //左连接操作
        Map<String, List<InvoiceDataDTO>> hsCodeDataMap = hsCodeData.stream().collect(Collectors.groupingBy(InvoiceDataDTO::getSku));

        List<InvoiceDataDTO> mergeData = new ArrayList<>();
        for (InvoiceDataDTO mainItem : data) {
            String key = mainItem.getSku();
            if (hsCodeDataMap.containsKey(key)) {
                List<InvoiceDataDTO> InvoiceDataDTOS = hsCodeDataMap.get(key);
                InvoiceDataDTOS.forEach(f -> {
                    InvoiceDataDTO newItem = new InvoiceDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setHscode(f.getHscode());
                    mergeData.add(newItem);
                });
            } else {
                mergeData.add(mainItem);
            }
        }

        return mergeData;
    }

    /**
     * 添加异常海关编码
     */
    private List<InvoiceDataDTO> addAbnormalHscode(List<InvoiceDataDTO> data) {
        // 处理没有海关编码的数据
        List<InvoiceDataDTO> withHsCode = data.stream()
                .filter(dto -> dto.getHscode() != null)
                .collect(Collectors.toList());
        List<InvoiceDataDTO> withoutHsCode = data.stream()
                .filter(dto -> dto.getHscode() == null)
                .collect(Collectors.toList());
        List<InvoiceDataDTO> hsCodeData = metaStkShipmentMapper.getHscodeDataByBelongsIsNull();

        //左连接操作
        Map<String, List<InvoiceDataDTO>> hsCodeDataMap = hsCodeData.stream().collect(Collectors.groupingBy(InvoiceDataDTO::getSku));

        List<InvoiceDataDTO> addHsCodeData = new ArrayList<>();
        for (InvoiceDataDTO mainItem : withoutHsCode) {
            String key = mainItem.getSku();
            if (hsCodeDataMap.containsKey(key)) {
                List<InvoiceDataDTO> InvoiceDataDTOS = hsCodeDataMap.get(key);
                InvoiceDataDTOS.forEach(f -> {
                    InvoiceDataDTO newItem = new InvoiceDataDTO();
                    BeanUtil.copyProperties(mainItem, newItem);
                    newItem.setHscode(f.getHscode());
                    addHsCodeData.add(newItem);
                });
            } else {
                addHsCodeData.add(mainItem);
            }
        }

        List<InvoiceDataDTO> AllHsCode = new ArrayList<>();
        AllHsCode.addAll(withHsCode);
        AllHsCode.addAll(addHsCodeData);
        return AllHsCode;
    }

    /**
     * 添加税号
     */
    public List<InvoiceDataDTO> addTaxid(List<InvoiceDataDTO> orig, List<InvoiceDataDTO> taxid) {

        //左连接操作
        Map<String, List<InvoiceDataDTO>> taxidDataMap = taxid.stream().collect(Collectors.groupingBy(InvoiceDataDTO::getCorp));
        List<InvoiceDataDTO> sellerTaxid = new ArrayList<>();
        for (InvoiceDataDTO mainItem : orig) {
            String key = mainItem.getFullseller();
            if (taxidDataMap.containsKey(key)) {
                List<InvoiceDataDTO> InvoiceDataDTOS = taxidDataMap.get(key);
                InvoiceDataDTOS.forEach(f -> {
                    InvoiceDataDTO newItem = new InvoiceDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setTaxid(f.getTaxid());
                    sellerTaxid.add(newItem);
                });
            } else {
                sellerTaxid.add(mainItem);
            }
        }
        sellerTaxid.forEach(f -> f.setSellerTaxId(f.getTaxid()));

        List<InvoiceDataDTO> buyerTaxid = new ArrayList<>();
        for (InvoiceDataDTO mainItem : sellerTaxid) {
            String key = mainItem.getFullbuyer();
            if (taxidDataMap.containsKey(key)) {
                List<InvoiceDataDTO> InvoiceDataDTOS = taxidDataMap.get(key);
                InvoiceDataDTOS.forEach(f -> {
                    InvoiceDataDTO newItem = new InvoiceDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setTaxid(f.getTaxid());
                    buyerTaxid.add(newItem);
                });
            } else {
                buyerTaxid.add(mainItem);
            }
        }
        buyerTaxid.forEach(f -> f.setBuyerTaxId(f.getTaxid()));

        return buyerTaxid;
    }

    /**
     * 转换为InvInvoice实体
     */
    public List<InvInvoice> convertToInvInvoice(List<InvoiceDataDTO> dataList) {
        return dataList.stream()
                .map(dto -> {
                    InvInvoice invoice = new InvInvoice();
                    invoice.setInvoicetype(dto.getType() != null ? dto.getType() : null);
                    invoice.setId(dto.getInvoiceId());
                    invoice.setInvoiceno(dto.getInvoiceNo());
                    invoice.setInvoicedate(dto.getInvoicedate());
                    invoice.setReportdate(dto.getReportdate());
                    invoice.setSeller(dto.getSeller());
                    invoice.setBuyer(dto.getBuyer());
                    invoice.setFromcountry(dto.getFromcountry());
                    invoice.setTocountry(dto.getTocountry());
                    invoice.setNettotal(dto.getPriceTotal());
                    invoice.setSellertaxid(dto.getSellerTaxId());
                    invoice.setBuyertaxid(dto.getBuyerTaxId());
                    invoice.setCreatetime(Date.from(java.time.LocalDateTime.now().atZone(java.time.ZoneId.systemDefault()).toInstant()));
                    return invoice;
                })
                .collect(Collectors.toList());
    }

    /**
     * 转换为InvInvoiceDtl实体
     */
    public List<InvInvoiceDtl> convertToInvInvoiceDtl(List<InvoiceDataDTO> dataList) {
        return dataList.stream()
                .map(dto -> {
                    InvInvoiceDtl detail = new InvInvoiceDtl();
                    detail.setId(UUID.randomUUID().toString().replace("-", "").toLowerCase());
                    detail.setInvoiceid(dto.getInvoiceId());
                    detail.setSku(dto.getSku());
                    detail.setPrice(dto.getPrice());
                    detail.setExportprice(dto.getExportprice());
                    detail.setOceanfee(dto.getOceanfee());
                    detail.setInvoicetype(dto.getType());
                    detail.setQty(dto.getQty());
                    detail.setHscode(dto.getHscode());
                    detail.setDescription(dto.getDescription());
                    detail.setWeight(dto.getWeight());
                    detail.setCreatetime(Date.from(java.time.LocalDateTime.now().atZone(java.time.ZoneId.systemDefault()).toInstant()));
                    return detail;
                })
                .collect(Collectors.toList());
    }

    /**
     * 批量插入发票主表数据
     */
    public void batchInsertInvoices(List<InvInvoice> records) {
        if (records.isEmpty()) {
            log.info("没有需要批量插入的发票主表数据");
            return;
        }

        try {
            invInvoiceMapper.insertBatch(records);
            log.info("批量插入发票主表数据完成，插入条数：{}", records.size());
        } catch (Exception e) {
            log.error("批量插入发票主表数据失败", e);
            throw new RuntimeException("批量插入发票主表数据失败", e);
        }
    }

    /**
     * 批量插入发票明细数据
     */
    public void batchInsertInvoiceDtls(List<InvInvoiceDtl> records) {
        if (records.isEmpty()) {
            log.info("没有需要批量插入的发票明细数据");
            return;
        }

        try {
            invInvoiceDtlMapper.insertBatch(records);
            log.info("批量插入发票明细数据完成，插入条数：{}", records.size());
        } catch (Exception e) {
            log.error("批量插入发票明细数据失败", e);
            throw new RuntimeException("批量插入发票明细数据失败", e);
        }
    }
}